package csm.sql;

import java.sql.Connection;
import java.sql.SQLException;

import csm.common.SMException;

/**
 * 
 * @author seungmun
 * @since 2006.1.18.
 * @version
 * @see
 */
public abstract class TransactionManager extends EntityBase
{
	boolean transactionState = false;

	/**
	 * 트랜잭션을 시작합니다.
	 * 
	 * @throws SQLException
	 *             (트랜잭션을 중복해서 시작하는 경우, 연결을 얻어오지 못하는 경우)
	 */
	public Connection beginTransaction() throws SMException
	{
		try
		{
			if (transactionState) throw new SMException("Transaction was already started." + this.getClass().getName());

			Connection cn = getConnection();

			this.setConnection(cn);

			cn.setAutoCommit(false);

			this.transactionState = true;

			return cn;
		}
		catch (SQLException e)
		{
			throw new SMException(e.getMessage(), e);
		}
		catch (Exception e)
		{
			throw new SMException(e.getMessage(), e);
		}
	}

	/**
	 * 활성화된 트랜잭션을 커밋합니다.
	 * 
	 * @throws SQLException
	 */
	public void commit() throws SMException
	{
		try
		{
			if (!transactionState) throw new SQLException("활성화된 트랜잭션이 없습니다." + this.getClass().getName());

			super.getInternalConnection().commit();
			super.getInternalConnection().setAutoCommit(true);
		}
		catch (SQLException e)
		{
			throw new SMException(e.getMessage(), e);
		}
		catch (Exception e)
		{
			throw new SMException(e.getMessage(), e);
		}
		finally
		{
			this.transactionState = false;
		}
	}

	/**
	 * 활성화된 트랜잭션을 롤백합니다.
	 * 
	 * @throws SQLException
	 */
	public void rollback() throws SMException
	{
		try
		{
			if (!transactionState) throw new SQLException("활성화된 트랜잭션이 없습니다." + this.getClass().getName());
			super.getInternalConnection().rollback();
			super.getInternalConnection().setAutoCommit(true);
		}
		catch (SQLException e)
		{
			throw new SMException(e.getMessage(), e);
		}
		catch (Exception e)
		{
			throw new SMException(e.getMessage(), e);
		}
		finally
		{
			this.transactionState = false;
		}
	}

	/*
	 * (비Javadoc) 이 메서드는 내부에서만 사용하고 외부에서 사용하지 않습니다.
	 */
	@Override
	protected Connection getInternalConnection() throws SQLException
	{
		throw new SQLException("이 메서드는 사용되지 않습니다." + this.getClass().getName());
	}

	/**
	 * 연결을 종료시킵니다.
	 * 
	 * @param cn
	 */
	protected void close(Connection cn) throws SMException
	{
		try
		{
			cn.setAutoCommit(false);
			cn.close();
		}
		catch (SQLException e)
		{
			throw new SMException(e.getMessage(), e);
		}
	}

	/**
	 * 내부에서 사용된 연결을 종료시킵니다.
	 */
	protected void closeConnection() throws SMException
	{
		try
		{
			super.getInternalConnection().setAutoCommit(false);
			super.getInternalConnection().close();
		}
		catch (SQLException e)
		{
			throw new SMException(e.getMessage(), e);
		}
		finally
		{
			this.transactionState = false;
		}
	}
}
